package com.loop.netty.codec2;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;

/**
 * @author zhangxiaolu
 * @since 2023-09-10 21:56
 */
public class NettyServer {

    public static void main(String[] args) {
        // 创建BossGroup 和 WorkerGroup
        // 说明
        // 创建两个线程组，bossGroup 只是处理连接请求，真正的和客户端业务处理，会交给workerGroup完成。
        // 两个都是无限循环
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        // 创建服务器端启动的对象，配置启动参数
        ServerBootstrap bootstrap = new ServerBootstrap();
        // 使用链式编程进行设置
        bootstrap.group(bossGroup, workerGroup) // 设置两个线程组
                .channel(NioServerSocketChannel.class) // 使用NioSocketChannel作为服务器的通道实现
                .option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列得到的连接个数
                .childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动的连接状态
                .childHandler(new ChannelInitializer<SocketChannel>() {// 创建一个通道测试对象（匿名对象）
                    // 给pipeline 设置处理器
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        // 加入 Protobuf 解码器，并指定解码对象类
                        ch.pipeline().addLast(new ProtobufDecoder(MyDataInfoBuf.MyDataInfo.getDefaultInstance()));
                        ch.pipeline().addLast(new NettyServerHandler());
                    }
                }); // 给我们的workerGroup 的 EventLoop 对应的管道设置处理器
        System.out.println("服务器 is ready");
        try {
            // 启动服务器
            ChannelFuture channelFuture = bootstrap.bind(6668).sync();

            // 给channelFuture注册 监听器，监控我们关心的事件
            channelFuture.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    System.out.println("监听端口 6668 成功");
                } else {
                    System.out.println("监听端口 6668 失败");
                }
            });

            // 监听服务器关闭监听
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
        System.out.println("服务器 is shutdown");
    }
}
